package com.kingyea.mobilepolice.apimanage.accesscontrol.handle;

import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.CacheLoader.InvalidCacheLoadException;
import com.google.common.collect.Lists;
import com.kingyea.mobilepolice.apimanage.accesscontrol.bean.AccessController;
import com.kingyea.mobilepolice.apimanage.accesscontrol.bean.CustomController;
import com.kingyea.mobilepolice.apimanage.accesscontrol.service.AccessControllerService;
import com.kingyea.mobilepolice.apimanage.accesscontrol.service.CustomControllerService;
import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;

/**
 * @author chenjw
 * @version v1.0.0
 * @description
 * @date Created in 2018/4/3 16:11
 */
@Service
public class DetailHadle {
    private static final Logger LOG = LoggerFactory.getLogger(DetailHadle.class);
    @Autowired
    private AccessControllerService accessControllerService;
    @Autowired
    private CustomControllerService customControllerService;


    /**
     * 获取校验项
     *
     * @param serviceId
     * @return
     */
    public List<FunctionName> getFunctionName(Integer serviceId) {
        List<FunctionName> functionName = null;
        try {
            AccessController accessControlInfo = getWholeAccessControlInfo(serviceId);
            functionName = (List<FunctionName>) ControllerHandleImpl.cache.get(serviceId + "_functionName", new Callable<List<FunctionName>>() {
                public List<FunctionName> call() {
                    List<FunctionName> list = Lists.newArrayList();
                    int switch_button = accessControlInfo.getSwitchButton();
                    FunctionName[] values = FunctionName.values();
                    for (int i = 0; i < values.length; i++) {
                        FunctionName functionName = values[i];
                        if (((switch_button & (0x1 << functionName.getCode())) >> functionName.getCode()) == 1) {
                            list.add(functionName);
                        }
                    }

                    return list;
                }
            });
        } catch (final Exception e) {
            return Lists.newArrayList();
        }
        return functionName;
    }


    /**
     * 获取全局的服务方信息
     *
     * @param serviceID
     * @return
     * @throws ExecutionException
     */
    public AccessController getWholeAccessControlInfo(final Integer serviceID) throws ExecutionException {
        AccessController accessControlInfo = new AccessController();
        accessControlInfo = (AccessController) ControllerHandleImpl.cache.get(serviceID + "_whole", new Callable<Object>() {

            @Override
            public Object call() throws Exception {
                AccessController accessControlInfos = null;
                accessControlInfos = accessControllerService.getByServiceId(serviceID);
                if ((accessControlInfos != null)) {
                    return accessControlInfos;
                } else {
                    return new AccessController();
                }
            }
        });
        return accessControlInfo;
    }

    /**
     * 得到限制访问的时间段
     *
     * @param senderID
     * @param serviceID
     * @param type
     * @return
     */
    public String getAccredit(Integer senderID, Integer serviceID, String type) {


        String cron = null;
        if (type.equals("special")) {// 单个请求方和服务方的时间段
            CustomController accredit = new CustomController();
            try {
                accredit = this.getAccreditApplication(senderID, serviceID);
            } catch (final ExecutionException e) {

                LOG.error("获取服务运行访问的时间段失败", e);
                return null;
            } /*catch (final InvalidCacheLoadException e) {
                LOG.error("服务运行访问的时间段为空", e);
                return null;
            }*/
            cron = accredit.getTimeSlot();
        } else {// 服务方全局的时间段
            AccessController accessControlInfo = new AccessController();
            try {
                accessControlInfo = this.getWholeAccessControlInfo(serviceID);
            } catch (final ExecutionException e) {
                LOG.error("服务方全局的时间段失败", e);
                return null;
            }/* catch (final InvalidCacheLoadException e) {
                LOG.error("服务方全局的时间段为空", e);
                return null;
            }*/
            cron = accessControlInfo.getTimeSlot();
        }
        return cron;
    }

    private CustomController getAccreditApplication(Integer senderID, Integer serviceID) throws ExecutionException {
        CustomController accredit = null;
        accredit = (CustomController) ControllerHandleImpl.cache.get(senderID + "_" + serviceID + "_accredit", new Callable<Object>() {

            @Override
            public Object call() {
                List<CustomController> accredit = null;
                CustomController cController = null;
                accredit = customControllerService.getByReqAndServiceId(senderID, serviceID);
                if ((accredit != null) && (accredit.size() > 0)) {
                    cController = accredit.get(0);
                }
                return cController;

            }
        });
        return accredit;
    }

    /**
     * 获取并校验ip黑白名单
     *
     * @param senderID
     * @param serviceID
     * @param requestIP
     * @return
     */
    public boolean getIpAuthen(Integer senderID, Integer serviceID, String requestIP) {
        AccessController accessControlInfo = null;
        try {
            accessControlInfo = this.getWholeAccessControlInfo(serviceID);
        } catch (final ExecutionException e) {
            LOG.error("获取IP黑白名单失败", e);
            return false;
        } catch (final CacheLoader.InvalidCacheLoadException e) {
            LOG.error("IP黑白名单为空", e);
            return false;
        }
        boolean flag = true;
        if (accessControlInfo == null) {
            return false;
        }

        // "".split(",").length为1 ！

        // IP白名单
        final String ipWhitesStr = accessControlInfo.getIpWhite();
        // IP白名单字符串不为空
        if (!Strings.isNullOrEmpty(ipWhitesStr)) {
            final String[] ipWhites = ipWhitesStr.split(";");
            if (ArrayUtils.contains(ipWhites, requestIP)) {// 是否在白名单里面
                return true;
            } else {
                int trueFlag = 0;
                for (final String ipWhite : ipWhites) {// 是否在白名单的网段里面
                    if (ipWhite.contains("/")) {
                        flag = this.isInRange(requestIP, ipWhite);
                        if (flag) {
                            trueFlag++;
                        }
                    }
                }
                flag = trueFlag > 0 ? true : false;
                return flag;
            }
        }
        // IP黑名单
        String[] ipBlcaks = null;
        if (Strings.isNullOrEmpty(accessControlInfo.getIpBlack())) {// 黑名单为空就没有限制
            return true;
        } else {
            ipBlcaks = accessControlInfo.getIpBlack().split(";");

        }


        if (ArrayUtils.contains(ipBlcaks, requestIP)) {
            return false;
        } else {
            for (final String ipBlcak : ipBlcaks) {
                boolean falseFlag;
                if (ipBlcak.contains("/")) {
                    falseFlag = this.isInRange(requestIP, ipBlcak);
                    if (falseFlag) {
                        return false;
                    }
                }
            }

        }
        return flag;

    }

    /**
     * 检测请求IP是否在名单中IP的网段内
     */
    private boolean isInRange(String requestIP, String cidr) {
        final String[] ips = requestIP.split("\\.");
        final int ipAddr = (Integer.parseInt(ips[0]) << 24) | (Integer.parseInt(ips[1]) << 16) | (Integer.parseInt(ips[2]) << 8) | Integer.parseInt(ips[3]);
        final int type = Integer.parseInt(cidr.replaceAll(".*/", ""));
        final int mask = 0xFFFFFFFF << (32 - type);
        final String cidrIp = cidr.replaceAll("/.*", "");
        final String[] cidrIps = cidrIp.split("\\.");
        final int cidrIpAddr = (Integer.parseInt(cidrIps[0]) << 24) | (Integer.parseInt(cidrIps[1]) << 16) | (Integer.parseInt(cidrIps[2]) << 8) | Integer.parseInt(cidrIps[3]);

        return (ipAddr & mask) == (cidrIpAddr & mask);
    }

    /**
     * 获取请求频率
     *
     * @param senderID
     * @param serviceID
     * @param type
     * @return
     */
    public String getRequestFrequency(Integer senderID, Integer serviceID, String type) {

        String frequency = null;
        if (type.equals("special")) {
            CustomController accredit = new CustomController();
            try {
                accredit = this.getAccreditApplication(senderID, serviceID);
            } catch (final ExecutionException e) {
                LOG.error("获取请求频率失败", e);
                return null;
            } catch (final InvalidCacheLoadException e) {
                LOG.error("请求频率为空", e);
                return null;
            }
            frequency = accredit.getFrequency();
        } else {
            AccessController accessControlInfo = new AccessController();
            try {
                accessControlInfo = this.getWholeAccessControlInfo(serviceID);
            } catch (final ExecutionException e) {
                LOG.error("获取全局请求频率失败", e);
                return null;
            } catch (final InvalidCacheLoadException e) {
                LOG.error("全局请求频率为空", e);
                return null;
            }
            frequency = accessControlInfo.getFrequency();
        }
        return frequency;
    }

    /**
     * 得到数据量限制
     *
     * @param serviceID
     * @return
     */
    public String getFilesMaxSize(Integer serviceID) {
        AccessController accessControlInfo = null;
        try {
            accessControlInfo = this.getWholeAccessControlInfo(serviceID);
        } catch (final ExecutionException e) {

            LOG.error("获取数据量大小限制失败", e);
            return null;
        } catch (final InvalidCacheLoadException e) {
            LOG.error("获取数据量大小限制为空", e);
            return null;
        }

        // fileSize = this.dao.getFilesMaxSize(serviceID);
        return accessControlInfo.getDatasize();
    }

    /**
     * 根据serviceid获取需要过滤的关键字
     *
     * @param serviceId
     * @return
     */
    public List<?> getKeyword(Integer serviceId) {
        AccessController accessControlInfo = null;
        try {
            accessControlInfo = this.getWholeAccessControlInfo(serviceId);
        } catch (final ExecutionException e) {
            LOG.error("获取全局关键字失败", e);
            return null;
        } catch (final InvalidCacheLoadException e) {
            LOG.error("全局关键字为空", e);
            return null;
        }

        final String keyWordId = accessControlInfo.getKeyword();
        if (Strings.isNullOrEmpty(keyWordId))
            return null;
        String keyStr = "(";
        String[] str = keyWordId.split("#");
        for (String id : str) {
            keyStr += "'" + id + "'" + ",";
        }
        final String keyworkStr = keyStr.substring(0, keyStr.length() - 1) + ")";

        List<Keyword> keyList = new ArrayList<Keyword>();

        try {
            keyList = (List<Keyword>) ControllerHandleImpl.cache.get(serviceId + "_keyList", new Callable<Object>() {

                @Override
                public Object call() throws Exception {
                    List<Keyword> keys = accessControllerService.getKeyworList(keyworkStr);
                    if (keys == null) {
                        keys = new ArrayList<>();
                    }

                    return keys;

                }
            });
        } catch (final ExecutionException e) {
            LOG.error("获取关键字失败", e);
            return null;
        } catch (final InvalidCacheLoadException e) {
            LOG.error("关键字为空", e);
            return null;
        }

        new StringBuffer();
        String[] both = {};

        for (int i = 0; i < keyList.size(); i++) {
            if (keyList.get(i).getStatus() != 1) {
                continue;
            }
            both = (String[]) ArrayUtils.addAll(both, keyList.get(i).getWordgroup().split("#"));
        }
        return Arrays.asList(both);
    }

    public List<Map> getParametricRule(Integer serviceId) {
        List<Map> map = new ArrayList<Map>();
        AccessController accessControlInfo = null;
        String reqParam = null;
        try {
            accessControlInfo = this.getWholeAccessControlInfo(serviceId);
        } catch (final ExecutionException e) {
            LOG.error("获取请求参数规则失败", e);
            return null;
        } catch (final InvalidCacheLoadException e) {
            LOG.error("获取请求参数规则失败", e);
            return null;
        }
        reqParam = accessControlInfo.getParamFilter();
        if (Strings.isNullOrEmpty(reqParam)) {
            return null;
        }
        List<Map> list = JSONObject.parseArray(reqParam, Map.class);

        return list;
    }
}
